#pragma once

enum SequenceType 
{ 
	HALTON=0, 
	FOLDED_HALTON=1, 
	HAMMERSLEY=2, 
	FOLDED_HAMMERSLEY=3, 
	POSSION_DISK=4, 
	BEST_CANDIDATE=5, 
	PENROSE=6 
};

class CGenRandomSeq
{
public:
	CGenRandomSeq(void);
	CGenRandomSeq(SequenceType sType, int iNum);
	virtual ~CGenRandomSeq(void) 
	{  
		ReleaseMemory();  
		LafortuneSmpls.RemoveAll();
		LafortuneScales.RemoveAll();
		WardSmpls.RemoveAll();
		WardScales.RemoveAll();
	}
	/// Generates a quasi-random number sequence using currSequenceType
	void genSequence();
	/// Generates Lafortune sample directions using the quasi-random numbers generated
	void genLafortuneSamples(float cxy, float cz, float n);
	/// Generates Ward sample directions using the quasi-random numbers generated
	void genWardSamples(float alphax, float alphay);

private:
	void genHaltonSequence();
	void genFoldedHaltonSequence();
	void genHammersleySequence();
	void genFoldedHammersleySequence();
	void genPossionDiskSequence();
	void genBestCandidateSequence();
	void genPenroseSequence();

	// Inversion code courtesy of Matt Pharr and Greg Humphries
	inline double FoldedRadicalInverse(int n, int base);
	inline double RadicalInverse(int n, int base);
	void ReleaseMemory() 
	{
		randnum.RemoveAll();
		randcos.RemoveAll();
		randsin.RemoveAll();
		randlog.RemoveAll();
	}
	void ReserveMemory()
	{
		for (unsigned int i = 0; i < m_iNumSamples; i++)
		{
			randnum.Add(0);
			randcos.Add(0);
			randsin.Add(0);
			randlog.Add(0);
		}
		
	}

public:
	SequenceType m_currSequenceType;
	unsigned int m_iNumSamples;	//Number of currently generated samples
	CGrowableArray<float> randnum;
	CGrowableArray<float> randcos;
	CGrowableArray<float> randsin;
	CGrowableArray<float> randlog;

	CGrowableArray<D3DXVECTOR4> LafortuneSmpls;
	CGrowableArray<float> LafortuneScales;
	unsigned int m_iNumLafortuneSmpls;
	CGrowableArray<D3DXVECTOR4> WardSmpls;
	CGrowableArray<float> WardScales;
	unsigned int m_iNumWardSmpls;
	

	static const float minrnd;
	static const float maxrnd;
};

